package com.itmuch.common.feignset.hystix;

import com.itmuch.common.cat.feign.FeignCat;
import com.netflix.hystrix.strategy.HystrixPlugins;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.util.concurrent.Callable;

public class QfHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {

private static Logger log = LoggerFactory.getLogger(QfHystrixConcurrencyStrategy.class);
	
public QfHystrixConcurrencyStrategy() {
    HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
}

@Override
public <T> Callable<T> wrapCallable(Callable<T> callable) {
    RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
    return new HystrixContextWrapper<T>(callable,requestAttributes);
}
	
public static class HystrixContextWrapper<V> implements Callable<V> {
    private  RequestAttributes parentRequest;
    private HystrixRequestContext parentHystrixRequestContext;
    private Callable<V> delegate;

    public HystrixContextWrapper(Callable<V> delegate, RequestAttributes requestAttributes) {
    	//参考HystrixContextCallable
        this.parentHystrixRequestContext = HystrixRequestContext.getContextForCurrentThread();
        this.delegate = delegate;
        this.parentRequest = requestAttributes;
        log.info("HystrixContextWrapper consutruct:before thread:" + Thread.currentThread().getName());
        log.info("HystrixContextWrapper consutruct:before  requestContext instatnce :"+QfHystrixRequestContext.getRequestVariableDefaultInstance());
        FeignCat.createMessageTree();//
    }

    @Override
    public V call() throws Exception {
        HystrixRequestContext existingState = HystrixRequestContext.getContextForCurrentThread();
        log.info("HystrixContextWrapper call after:" + Thread.currentThread().getName());
        log.info("hystrixRequestContext call 1:" + parentHystrixRequestContext);
        log.info("hystrixRequestContext call 2:" + existingState);
    	try {
    		//把子类的线程绑定到父类的上下文了，所以下面的子类就能取到父类的数据了
            HystrixRequestContext.setContextOnCurrentThread(parentHystrixRequestContext);
            RequestContextHolder.setRequestAttributes(parentRequest);
            return this.delegate.call();
        } finally {
            HystrixRequestContext.setContextOnCurrentThread(existingState);
            RequestContextHolder.resetRequestAttributes();
        }
    }
}
}